package com.xxg.socket.impl;

import com.xxg.socket.YmaClient;
import com.xxg.socket.YmaConfig;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by game group on 2020/12/23.
 */
public abstract class NettySocketClient extends SimpleChannelInboundHandler<byte[]> implements YmaClient {
    private static final Logger log = LoggerFactory.getLogger(NettySocketClient.class);


    private final YmaConfig config;
    private Channel channel;
    private ChannelHandlerContext ctx;

    public NettySocketClient(YmaConfig config){
        this.config = config;
    }

    public NettySocketClient(){
        this(new DefaultYmaClientConfig());
    }

    @Override
    public void connect() {

        Bootstrap b = new Bootstrap();
        b.group(config.getWorkerGroup()).channel(NioSocketChannel.class)
            .handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast(new ByteArrayEncoder());
                    pipeline.addLast(new ByteArrayDecoder());
                    pipeline.addLast(NettySocketClient.this);
                }
            });

        try {
            ChannelFuture future = b.connect(config.getSocketAddress()).sync();
            future.addListener(new ChannelFutureListener() {

                @Override
                public void operationComplete(ChannelFuture arg0) throws Exception {
                    if (future.isSuccess()) {
                        System.out.println("连接服务器成功");

                    } else {
                        System.out.println("连接服务器失败");
                        future.cause().printStackTrace();
                        config.getWorkerGroup().shutdownGracefully(); //关闭线程组
                    }
                }
            });

            this.channel = future.channel();
        } catch (InterruptedException e) {
            disConnect();
        }
    }

    @Override
    public void disConnect() {
        if(channel != null && channel.isOpen()){
            channel.close().addListener(f -> {
                log.info("Shutdown dispatcher success...");
                config.getWorkerGroup().shutdownGracefully();
            });
        }
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, byte[] response) throws Exception {
        send(onMessage(response));
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);

        this.ctx = ctx;
        send(onOpen());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        onError(cause);
        ctx.close();
    }

    @Override
    public Object onOpen() {
        return null;
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onClose() {

    }

    @Override
    public void send(Object message) {
        if(null != message) ctx.writeAndFlush(message);
    }
}
